package cmd

import (
	"gitee.com/igolang/imoney/internal/core"
	"gitee.com/igolang/imoney/internal/core/client"
	"gitee.com/igolang/pkg/xutils"
	"github.com/spf13/cobra"
	"gorm.io/gen"
	"gorm.io/gorm"
	"os"
	"path/filepath"
	"slices"
	"strings"
	"unicode"
)

var (
	gDao bool
)

var genCmd = &cobra.Command{
	Use:   "gen",
	Short: "gen code",
	Long:  "生成代码，详见参数",
	PreRun: func(cmd *cobra.Command, args []string) {
		// 初始化
		core.Init()
	},
	Run: func(cmd *cobra.Command, args []string) {
		name := client.DefaultMysql
		if len(args) > 0 {
			name = args[0]
		}
		if gDao {
			genDao(name)
		}
	},
	PostRun: func(cmd *cobra.Command, args []string) {
		core.Shutdown()
	},
}

func genDao(name string) {
	log.Printf("generate %s models start\n", name)
	db := client.DB(name)
	if db == nil {
		log.Fatalln("gen dao db nil, name:", name)
	}

	outBasePath := filepath.Join(xutils.CurrentAbPath(), "internal/models")
	outQueryPath := filepath.Join(outBasePath, "dao")
	outModelPath := filepath.Join(outBasePath, "model")

	g := gen.NewGenerator(gen.Config{
		OutPath:      outQueryPath,
		ModelPkgPath: outModelPath,
		//FieldNullable:     true,
		FieldWithTypeTag:  true,
		FieldWithIndexTag: true,
		Mode:              gen.WithoutContext | gen.WithDefaultQuery,
	})
	opts := []gen.ModelOpt{
		gen.FieldGenType("create_time", "Time"),
		gen.FieldGenType("update_time", "Time"),
		gen.FieldNewTagWithNS("form", func(columnName string) string {
			return genCase2Camel(columnName)
		}),
		//gen.FieldNewTagWithNS("mapstructure", func(columnName string) string {
		//	return columnName
		//}),
	}
	g.WithOpts(opts...)
	g.WithDataTypeMap(dataMap())
	g.WithJSONTagNameStrategy(func(columnName string) (tagContent string) {
		if columnName == "password" {
			return "-"
		}
		return genCase2Camel(columnName)
	})

	g.UseDB(db)

	g.ApplyBasic(g.GenerateAllTable()...)
	g.Execute()
	// 删除多余的表
	tables, err := db.Migrator().GetTables()
	if err != nil {
		log.Fatalln(err)
	}
	formatFile(outQueryPath, tables)
	formatFile(outModelPath, tables)
}

func formatFile(outPath string, tables []string) {
	// 获取目录下的文件
	files, _ := os.ReadDir(outPath)
	//modelFiles, _ := os.ReadDir(outModelPath)
	for _, v := range files {
		genName := v.Name()
		if !strings.Contains(genName, ".gen.go") {
			continue
		}
		if !slices.Contains(tables, strings.ReplaceAll(genName, ".gen.go", "")) {
			rfile := filepath.Join(outPath, v.Name())
			log.Println("remove file:", rfile, os.Remove(rfile))
		}
	}
}

func dataMap() map[string]func(columnType gorm.ColumnType) (dataType string) {
	return map[string]func(columnType gorm.ColumnType) (dataType string){
		"int": func(columnType gorm.ColumnType) (dataType string) {
			return "int64"
		},
		"tinyint": func(columnType gorm.ColumnType) (dataType string) {
			return "int64"
		},
		"bigint": func(columnType gorm.ColumnType) (dataType string) {
			return "int64"
		},
		"datetime": func(columnType gorm.ColumnType) (dataType string) {
			return "xtime.Time"
		},
		"date": func(columnType gorm.ColumnType) (dataType string) {
			return "xtime.Date"
		},
		"timestamp": func(columnType gorm.ColumnType) (dataType string) {
			return "xtime.Time"
		},
	}
}

func genCase2Camel(columnName string) string {
	name := strings.Replace(columnName, "_", " ", -1)
	name = strings.Title(name)
	name = strings.Replace(name, " ", "", -1)
	for i, v := range name {
		return string(unicode.ToLower(v)) + name[i+1:]
	}

	return ""
}

func init() {
	genCmd.PersistentFlags().BoolVarP(&gDao, "dao", "d", false, "生成dao操作代码")
}
